package com.ccrc.base.dao.impl;

import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

import com.ccrc.base.dao.GenericDao;
import com.ccrc.lang.Paging;



public class GenericDaoImpl implements GenericDao {
	
	/**
     * 使用的SessionFactory
     */
    protected SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /**
     * 获得当前上下文Session
     * @return
     */
    protected Session session() {
        return this.sessionFactory.getCurrentSession();
    }
    
	/**
	 * 删除数据对象
	 */
	@Override
	public void delete(Object obj) {
		session().delete(obj);
	}
	
	/**
	 * 保存数据对象，用于新建
	 */
	@Override
	public Serializable save(Object obj) {
		return session().save(obj);
	}
	
	/**
	 * 更新数据对象，用于修改
	 */
	@Override
	public void update(Object obj) {
		session().update(obj);
	}
	
	/**
	 * 从数据库重新读取对象
	 */
	@Override
	public void refresh(Object obj) {
		session().refresh(obj);
	}
	
	/**
	 * 
	 * @param hql
	 * @return
	 */
	protected Query createQuery(String hql){
		Query q = session().createQuery(hql);
	    return q;
	}
	
	/**
     * 创建Native SQL查询
     * @param sql
     * @return
     */
    protected SQLQuery createSQLQuery(String sql){
        return session().createSQLQuery(sql);
    }
	
	/**
	 * 根据id得到对象
	 * @param <E>
	 * @param clazz
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <E> E get(Class<E> clazz, Serializable id){
        return (E)session().get(clazz, id);
    }
	
	/**
	 * 根据id删除对象
	 * @param clazz
	 * @param id
	 */
	protected void deleteById(Class<?> clazz, Serializable id){
		Session session = session();
        Object obj = session().get(clazz, id);
        if (obj != null) {
        	session.delete(obj);
        }
    }
	
	 /**
     * 创建TOP查询
     * @param maxResults 最大数量
     * @param clazz 返回实体对象类
     */
    protected <E> TopQuery<E> topQuery(int maxResults, Class<E> clazz){
        return new TopQuery<E>(maxResults, clazz, null);
    }

    /**
     * 创建TOP查询
     * @param maxResults 最大数量
     * @param clazz 返回实体对象类
     */
    protected <E> TopQuery<E> topQuery(int maxResults, Class<E> clazz, String cacheRegion){
        return new TopQuery<E>(maxResults, clazz, cacheRegion);
    }
	
	 /**
     * 创建分页查询
     * @param paging 分页对象
     * @param clazz 返回实体对象类
     */
    protected <E> PagingQuery<E> pagingQuery(Paging paging, Class<E> clazz){
        return new PagingQuery<E>(paging, clazz, null);
    }

    /**
     * 创建分页查询
     * @param paging 分页对象
     * @param clazz 返回实体对象类
     * @param cacheRegion 缓存保存区域
     */
    protected <E> PagingQuery<E> pagingQuery(Paging paging, Class<E> clazz, String cacheRegion){
        return new PagingQuery<E>(paging, clazz, cacheRegion);
    }
	
	protected class TopQuery<T> implements Serializable {
        private static final long serialVersionUID = 8331182441328915375L;

        String cacheRegion;

        Class<T> clazz;

        List<Criterion> criterions = null;

        List<Order> orders = null;

        List<Alias> aliases = null;

        int maxResults;

        public TopQuery(int maxResults, Class<T> clazz, String cacheRegion){
            this.maxResults = maxResults;
            this.clazz = clazz;
            this.cacheRegion = cacheRegion;
        }

        public TopQuery<T> add(Criterion c){
            if (criterions == null) {
                criterions = new LinkedList<Criterion>();
            }
            criterions.add(c);
            return this;
        }

        public TopQuery<T> asc(String field){
            return add(Order.asc(field));
        }

        public TopQuery<T> desc(String field){
            return add(Order.desc(field));
        }

        public TopQuery<T> alias(String field, String alias){
            if (aliases == null) {
                aliases = new LinkedList<Alias>();
            }
            aliases.add(new Alias(field, alias));
            return this;
        }

        @SuppressWarnings("unchecked")
        public List<T> list(){
            Criteria c = criteria(true);
            if (maxResults > 0) {
                c.setMaxResults(maxResults);
            }
            return c.list();
        }

        protected Criteria criteria(boolean sortable){
            Criteria c = createCriteria(clazz);
            if (criterions != null) {
                if (aliases != null) {
                    for (Alias a : aliases) {
                        c.createAlias(a.field, a.alias);
                    }
                }
                for (Criterion ctn : criterions) {
                    c.add(ctn);
                }
            }
            if (cacheRegion != null) {
                c.setCacheRegion(cacheRegion);
            }

            if (sortable && orders != null) {
                for (Order o : orders) {
                    c.addOrder(o);
                }
            }

            return c;
        }

        private TopQuery<T> add(Order o){
            if (orders == null) {
                orders = new LinkedList<Order>();
            }
            orders.add(o);
            return this;
        }
    }

    protected class PagingQuery<T> extends TopQuery<T> implements Serializable {
        private static final long serialVersionUID = 397003060855915658L;

        Paging paging;

        public PagingQuery(Paging paging, Class<T> clazz, String cacheRegion){
            super(paging.getMaxResults(), clazz, cacheRegion);
            this.paging = paging;

        }

        @SuppressWarnings("unchecked")
        @Override
        public List<T> list(){
            boolean query = true;
            // 统计数据总数
            if (paging.isCount()) {
                int totalCount = ((Number) criteria(false).setProjection(Projections.rowCount()).uniqueResult()).intValue();
                paging.setTotalCount(totalCount);
                if (totalCount <= paging.getFirstResult()) {
                    query = false;
                }
            }

            // 查询当前页数据
            List<T> results = Collections.EMPTY_LIST;
            if (query) {
                Criteria c = criteria(true).setFirstResult(paging.getFirstResult()).setMaxResults(paging.getMaxResults());
                results = c.list();
            }
            
            paging.setResults(results);
            
            return results;
        }

    }
    
    private class Alias implements Serializable {

        private static final long serialVersionUID = 5152383719243132307L;

        private String field;

        private String alias;

        public Alias(String field, String alias){
            this.field = field;
            this.alias = alias;
        }
    }
    
    /**
     * 创建带缓存的QBC查询
     * @param clazz 查询的实体类型
     * @return
     */
    protected Criteria createCriteria(Class<?> clazz){
        return session().createCriteria(clazz).setCacheable(true);
    }

	@Override
	public void saveOrUpdate(Object obj) {
		session().saveOrUpdate(obj);
	}
    
	
}
